#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
BLE通知调试脚本
该脚本用于详细诊断和解决BLE通知注册失败问题
"""

import asyncio
import sys
from bleak import BleakClient, BleakScanner


class BLENotifyDebugger:
    """BLE通知调试器"""
    
    def __init__(self, device_address=None):
        """
        初始化调试器
        
        Args:
            device_address (str): BLE设备地址，如果为None则扫描设备
        """
        self.device_address = device_address
        self.client = None
        self.connected = False
        self.services = None
        
    async def scan_devices(self, timeout=5.0):
        """
        扫描附近的BLE设备
        
        Args:
            timeout (float): 扫描超时时间（秒）
            
        Returns:
            list: 设备列表
        """
        print("正在扫描附近的BLE设备...")
        devices = await BleakScanner.discover(timeout=timeout)
        
        if not devices:
            print("未发现任何BLE设备")
            return []
            
        print(f"发现 {len(devices)} 个设备:")
        for i, device in enumerate(devices):
            print(f"  [{i}] {device.name or 'Unknown'} ({device.address})")
            
        return devices
        
    async def connect(self):
        """连接到BLE设备"""
        try:
            if not self.device_address:
                print("错误: 未指定设备地址")
                return False
                
            print(f"正在连接到BLE设备 ({self.device_address})...")
            self.client = BleakClient(self.device_address)
            await self.client.connect()
            self.connected = True
            print("连接成功!")
            return True
        except Exception as e:
            print(f"连接失败: {e}")
            self.connected = False
            return False
            
    async def discover_services_detailed(self):
        """详细发现设备的服务和特征"""
        if not self.connected:
            print("错误: 设备未连接")
            return False
            
        try:
            print("\n正在详细发现服务和特征...")
            self.services = self.client.services
            
            for service in self.services:
                print(f"\n  Service: {service.uuid}")
                print(f"    Description: {service.description}")
                
                for char in service.characteristics:
                    print(f"    Characteristic: {char.uuid}")
                    print(f"      Properties: {char.properties}")
                    print(f"      Description: {char.description}")
                    
                    # 显示描述符信息
                    for descriptor in char.descriptors:
                        print(f"      Descriptor: {descriptor.uuid}")
                        print(f"        Description: {descriptor.description}")
                        
            return True
        except Exception as e:
            print(f"服务发现失败: {e}")
            return False
            
    async def try_enable_notifications(self):
        """尝试启用所有支持通知的特征"""
        if not self.connected or not self.services:
            print("错误: 设备未连接或未发现服务")
            return False
            
        notification_chars = []
        
        # 收集所有支持通知的特征
        for service in self.services:
            for char in service.characteristics:
                if "notify" in char.properties or "indicate" in char.properties:
                    notification_chars.append(char)
                    
        if not notification_chars:
            print("未找到支持通知的特征")
            return False
            
        print(f"\n找到 {len(notification_chars)} 个支持通知的特征:")
        
        # 尝试为每个特征启用通知
        for i, char in enumerate(notification_chars):
            print(f"\n[{i+1}] 尝试启用通知: {char.uuid}")
            print(f"    属性: {char.properties}")
            
            try:
                # 尝试启用通知
                await self.client.start_notify(char.uuid, self.notification_handler)
                print(f"    ✓ 通知启用成功")
                
                # 等待一段时间看是否有数据
                print("    等待通知数据(3秒)...")
                await asyncio.sleep(3)
                
                # 停止通知
                await self.client.stop_notify(char.uuid)
                print(f"    ✓ 通知停止成功")
                
            except Exception as e:
                print(f"    ✗ 通知启用失败: {e}")
                
        return True
        
    def notification_handler(self, sender, data):
        """通知处理函数"""
        print(f"    [数据接收] 特征: {sender}")
        print(f"               数据长度: {len(data)} 字节")
        
        # 尝试解码
        try:
            text = data.decode('utf-8')
            print(f"               文本内容: {text}")
        except UnicodeDecodeError:
            print(f"               十六进制内容: 0x{data.hex()}")
            
    async def read_characteristics(self):
        """读取所有可读特征的值"""
        if not self.connected or not self.services:
            print("错误: 设备未连接或未发现服务")
            return False
            
        readable_chars = []
        
        # 收集所有可读特征
        for service in self.services:
            for char in service.characteristics:
                if "read" in char.properties:
                    readable_chars.append(char)
                    
        if not readable_chars:
            print("未找到可读特征")
            return False
            
        print(f"\n找到 {len(readable_chars)} 个可读特征:")
        
        # 尝试读取每个特征
        for i, char in enumerate(readable_chars):
            print(f"\n[{i+1}] 尝试读取: {char.uuid}")
            print(f"    属性: {char.properties}")
            
            try:
                data = await self.client.read_gatt_char(char.uuid)
                print(f"    ✓ 读取成功")
                
                # 尝试解码
                try:
                    text = data.decode('utf-8')
                    print(f"      文本内容: {text}")
                except UnicodeDecodeError:
                    print(f"      十六进制内容: 0x{data.hex()}")
                    
            except Exception as e:
                print(f"    ✗ 读取失败: {e}")
                
        return True
        
    async def run_debug(self):
        """运行调试"""
        try:
            # 如果没有指定设备地址，则扫描设备
            if not self.device_address:
                devices = await self.scan_devices()
                if not devices:
                    return
                    
                # 选择第一个设备进行测试
                selected_device = devices[0]
                self.device_address = selected_device.address
                print(f"选择设备: {selected_device.name or 'Unknown'} ({self.device_address})")
                
            # 连接到设备
            if not await self.connect():
                return
                
            # 详细发现服务
            await self.discover_services_detailed()
            
            # 读取可读特征
            await self.read_characteristics()
            
            # 尝试启用通知
            await self.try_enable_notifications()
            
        except KeyboardInterrupt:
            print("\n用户中断调试")
        except Exception as e:
            print(f"调试过程中出错: {e}")
        finally:
            # 断开连接
            if self.client and self.connected:
                await self.client.disconnect()
                self.connected = False
                print("\n已断开连接")


async def main():
    """主函数"""
    # 检查命令行参数
    device_address = None
    if len(sys.argv) > 1:
        device_address = sys.argv[1]
        
    # 创建调试器并运行调试
    debugger = BLENotifyDebugger(device_address)
    await debugger.run_debug()


if __name__ == "__main__":
    print("BLE通知调试工具")
    print("=" * 30)
    
    # 运行异步主函数
    asyncio.run(main())
    
    print("\n调试完成")